package net.protocol.diameter.avp;

import net.protocol.common.coding.ByteMe;

/**
 * <h3>Attribute-Value Pairs (AVP)</h3>
 * <pre>
 * Represents attribute value pair as defined in RFC 6733.
 * 	   Packet format
 *
 *      0                   1                   2                   3
 *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *     |                           AVP Code                            |
 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *     |V M P r r r r r|                  AVP Length                   |
 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *     |                        Vendor-ID (opt)                        |
 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *     |    Data ...
 *     +-+-+-+-+-+-+-+-+
 *
 *     AVP Code
 *        The AVP Code, combined with the Vendor-Id field, identifies the attribute uniquely.
 *
 *     AVP Flags
 *     	  For simplicity, 'V' Bit Means Vendor Specific; 'M' Bit means Mandatory; 'P' Bit means Protected.
 *        The 'V' bit, known as the Vendor-Specific bit, indicates whether the optional Vendor-ID field is present in the AVP header.
 *        When set the AVP Code belongs to the specific vendor code address space.
 *
 *        The 'M' Bit, known as the Mandatory bit, indicates whether support of the AVP is required.
 *        If an AVP with the 'M' bit set is received by a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized,
 *        the message MUST be rejected. Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs.
 *
 *        The 'P' bit indicates the need for encryption for end-to-end security.
 *
 *     AVP Length
 *        AVPHeaderLength(at least 8 | 12 if the 'V' bit is enabled) + AVPDataLength.
 * </pre>
 *
 * @author jinhongw@gmail.com
 * @see <a href="http://tools.ietf.org/html/rfc6733#page-40">Diameter Base Protocol - Diameter AVPs</a>
 * @see <a href="http://en.wikipedia.org/wiki/Diameter_%28protocol%29">Diameter (protocol)</a>
 */
public interface AVP<E> extends ByteMe {

    /**
     * @return AVP Code.
     */
    int getCode();

    /**
     * @return Vendor-ID (opt).
     */
    int getVendorId();

    /**
     * Indicates whether the optional Vendor-ID field is present in the AVP header.
     *
     * @return a <code>boolean</code> indicating whether or not 'V' Bit is enabled.
     */
    boolean isVendorId();

    /**
     * Indicates whether support of the AVP is required.
     *
     * @return a <code>boolean</code> indicating whether or not 'M' Bit is enabled.
     */
    boolean isMandatory();

    /**
     * Indicates the need for encryption for end-to-end security.
     *
     * @return a <code>boolean</code> indicating whether or not 'P' Bit is enabled.
     */
    boolean isProtected();

    /**
     * The 'M' Bit if set means Mandatory.
     *
     * @param flag <code>true</code> to set 'M' Bit,<code>false</code> to disable.
     */
    void setMandatory(boolean flag);

    /**
     * The 'P' bit if set means Protected.
     *
     * @param flag <code>true</code> to set 'P' Bit,<code>false</code> to disable.
     */
    void setProtected(boolean flag);

    /**
     * <pre>
     * Indicates the number of octets in this AVP including the
     * AVP Code, AVP Length, AVP Flags, Vendor-ID (opt)) and the AVP Data.
     * <pre/>
     *
     * @return Length = AVPHeaderLength + AVPDataLength.
     */
    int getLength();

    /**
     * @return AVP Header Length except AVP Data.
     */
    int getHeaderLength();

    /**
     * @return AVP Data Length.
     */
    int getDataLength();

    /**
     * @return AVP Data Object.
     */
    E getData();

    /**
     * @return AVP Data bytes.
     */
    byte[] getDataBytes();

    /**
     * Indicates AVP whether or not Group AVP.
     *
     * @return a <code>boolean</code> indicating AVP whether or not Group AVP.
     */
    boolean isGroup();

    /**
     * @return AVP Data Formats
     */
    DataFormat getType();

    /**
     * @return AVP Attribute Name
     */
    String getName();
}